#!/usr/bin/env python

# This is a dbus script to show a docklet for Finch. This should work
# for any 'compatible' purple client.
#
# By 'compatible', I mean any client that sets and updates the
# "unseen-count" data on the conversations.
#
# It allows doing the following things:
#    - It allows changing status.
#    - It shows the current status and info about unread messages in
#      the tooltip.
#    - It can blink on unread IM/Chat messages, and it allows canging
#      the preference for that.
#
# It requires GTK+ 2.10 or above, since it uses GtkStatusIcon.
#
# Sadrul <sadrul@pidgin.im>

from __future__ import absolute_import, division, print_function

import os  # to get the pkg-config output

import pygtk
pygtk.require("2.0")  # noqa
import gtk
import dbus
import dbus.glib


bus = dbus.SessionBus()
obj = bus.get_object("im.pidgin.purple.PurpleService",
                     "/im/pidgin/purple/PurpleObject")
purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")


def pack_image_label(menu, image, label):
    item = gtk.ImageMenuItem(label)
    if image:
        img = gtk.Image()
        img.set_from_stock(image, 1)
        item.set_image(img)
    menu.append(item)
    return item


def activate_primitive_status(item, status):
    saved = purple.PurpleSavedstatusFindTransientByTypeAndMessage(status, "")
    if not saved:
        saved = purple.PurpleSavedstatusNew("", status)
    purple.PurpleSavedstatusActivate(saved)


def activate_popular_status(item, time):
    saved = purple.PurpleSavedstatusFindByCreationTime(time)
    if saved:
        purple.PurpleSavedstatusActivate(saved)


def generate_status_menu(menu):
    item = gtk.MenuItem("Available")
    item.connect("activate", activate_primitive_status, 2)
    menu.append(item)

    item = gtk.MenuItem("Away")
    item.connect("activate", activate_primitive_status, 5)
    menu.append(item)

    item = gtk.MenuItem("Invisible")
    item.connect("activate", activate_primitive_status, 4)
    menu.append(item)

    item = gtk.MenuItem("Offline")
    item.connect("activate", activate_primitive_status, 1)
    menu.append(item)

    menu.append(gtk.MenuItem())

    popular = purple.PurpleSavedstatusesGetPopular(10)
    for pop in popular:
        title = purple.PurpleSavedstatusGetTitle(pop).replace('_', '__')
        item = gtk.MenuItem(title)
        item.set_data("timestamp",
                      purple.PurpleSavedstatusGetCreationTime(pop))
        item.connect("activate", activate_popular_status,
                     purple.PurpleSavedstatusGetCreationTime(pop))
        menu.append(item)


def toggle_pref(item, pref):
    purple.PurplePrefsSetBool(pref, item.get_active())


def quit_finch(item, null):
    # XXX: Ask first
    purple.PurpleCoreQuit()
    gtk.main_quit()


def close_docklet(item, null):
    gtk.main_quit()


def popup_menu(icon, button, tm, none):
    menu = gtk.Menu()

    # item = gtk.ImageMenuItem(gtk.STOCK_QUIT)
    # item.connect("activate", quit_finch, None)
    # menu.append(item)

    item = gtk.ImageMenuItem(gtk.STOCK_CLOSE)
    item.connect("activate", close_docklet, None)
    menu.append(item)

    menu.append(gtk.MenuItem())

    item = gtk.CheckMenuItem("Blink for unread IM")
    item.set_active(
        purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/im"))
    item.connect("activate", toggle_pref, "/plugins/dbus/docklet/blink/im")
    menu.append(item)

    item = gtk.CheckMenuItem("Blink for unread Chats")
    item.set_active(
        purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/chat"))
    item.connect("activate", toggle_pref, "/plugins/dbus/docklet/blink/chat")
    menu.append(item)

    menu.append(gtk.MenuItem())

    # item = pack_image_label(menu, None, "Change Status...")
    item = gtk.MenuItem("Change Status...")
    menu.append(item)
    submenu = gtk.Menu()
    item.set_submenu(submenu)
    generate_status_menu(submenu)

    menu.show_all()
    menu.popup(None, None, None, button, tm)


def get_status_message():
    status_names = {
        1: 'Offline',
        2: 'Available',
        4: 'Invisible',
        5: 'Away',
    }

    status = purple.PurpleSavedstatusGetCurrent()
    msg = purple.PurpleSavedstatusGetMessage(status)
    if msg and len(msg) > 0:
        text = msg + " "
    else:
        text = ""
    text += "(" + status_names[purple.PurpleSavedstatusGetType(status)] + ")"
    return text


def detect_unread_conversations():
    im = purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/im")
    chat = purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/chat")
    tooltip = ""
    blink = False
    if im and chat:
        convs = purple.PurpleGetConversations()
    elif im:
        convs = purple.PurpleGetIms()
    elif chat:
        convs = purple.PurpleGetChats()
    else:
        convs = None
    for conv in convs:
        count = purple.PurpleConversationGetData(conv, "unseen-count")
        if count and count > 0:
            blink = True
            tooltip += "\n%s (%d)" % (purple.PurpleConversationGetName(conv),
                                      count)
    t.set_from_file(path + "/share/pixmaps/pidgin.png")
    if blink:
        # I hate this icon
        # t.set_from_file(path +
        #                 "/share/pixmaps/pidgin/tray/22/tray-message.png")
        tooltip = "\nUnread Messages:" + tooltip
    # There's going to be some way to expose the client's display name in
    # 2.1.0. Use that instead of hardcoding Finch here.
    t.set_tooltip("Finch: " + get_status_message() + tooltip)
    t.set_blinking(blink)


def conversation_updated(conv, type):
    detect_unread_conversations()


def savedstatus_changed(new, old):
    # Change the icon for status perhaps?
    detect_unread_conversations()


def init_prefs():
    if not purple.PurplePrefsExists("/plugins/dbus/docklet/blink"):
        purple.PurplePrefsAddNone("/plugins")
        purple.PurplePrefsAddNone("/plugins/dbus")
        purple.PurplePrefsAddNone("/plugins/dbus/docklet")
        purple.PurplePrefsAddNone("/plugins/dbus/docklet/blink")
        purple.PurplePrefsAddBool("/plugins/dbus/docklet/blink/im", True)
        purple.PurplePrefsAddBool("/plugins/dbus/docklet/blink/chat", True)


pkg = os.popen("pkg-config --variable=prefix pidgin")
path = pkg.readline().rstrip()

bus.add_signal_receiver(conversation_updated,
                        dbus_interface="im.pidgin.purple.PurpleInterface",
                        signal_name="ConversationUpdated")

bus.add_signal_receiver(savedstatus_changed,
                        dbus_interface="im.pidgin.purple.PurpleInterface",
                        signal_name="SavedstatusChanged")

t = gtk.StatusIcon()
t.connect("popup-menu", popup_menu, None)

try:
    init_prefs()
    detect_unread_conversations()
    gtk.main()
except:
    dialog = gtk.Dialog("pietray: Error", None,
                        gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_MODAL,
                        ("Close", gtk.RESPONSE_CLOSE))
    dialog.set_resizable(False)
    error_label = gtk.Label("There was some error. Perhaps a purple client is "
                            "not running.")
    dialog.vbox.pack_start(error_label, False, False, 0)
    dialog.show_all()
    dialog.run()
